﻿/// <reference path="../../Core.ts" />

module Supernova {

    export class CreateShipPanel {

        public sliderVisibleValues = 8;

        public parent;

        public root = new UI.Panel({ left: 140, top: 10, right: 120, bottom: 10, visible: false });

        public populationSlider = new UI.Slider({ left: 0, width: 350, top: 0, height: 30, text: 'Colony Population', categoryMultiplier: 2.25, slotMultiplier: 0.25, stats: [{ name: 'Population', lookup: config.slotData.colony, suffix: 'pod' }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public terraformingSlider = new UI.Slider({ left: 0, width: 350, top: 40, height: 30, text: 'Terraforming', categoryMultiplier: 0.5, slotMultiplier: 1, stats: [{ name: 'Terraform' }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public scanningSlider = new UI.Slider({ left: 0, width: 350, top: 80, height: 30, text: 'Scanning Range', categoryMultiplier: 0.5, slotMultiplier: 0.75, stats: [{ name: 'Scanning Range', lookup: config.slotData.scanner, suffix: 'AU' }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public speedSlider = new UI.Slider({ left: 0, width: 350, top: 120, height: 30, text: 'Speed', categoryMultiplier: 0.5, slotMultiplier: 1, stats: [{ name: 'Speed', lookup: config.slotData.speeds, suffix: 'AU/s' }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public armorSlider = new UI.Slider({ left: 0, width: 350, top: 160, height: 30, text: 'Armor', categoryMultiplier: 0.75, slotMultiplier: 1, stats: [{ name: 'Armor', lookup: config.slotData.armor }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public shieldsSlider = new UI.Slider({ left: 0, width: 350, top: 200, height: 30, text: 'Shields', categoryMultiplier: 1, slotMultiplier: 1, stats: [{ name: 'Shields', lookup: config.slotData.shields }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public attackSlider = new UI.Slider({ left: 0, width: 350, top: 240, height: 30, text: 'Attack Power', categoryMultiplier: 1, slotMultiplier: 0.9, stats: [{ name: 'Attack Power', lookup: config.slotData.attackPower }, { name: 'Attack Radius', lookup: config.slotData.attackRadius, suffix: 'AU' }, { name: 'Attack Delay', lookup: config.slotData.attackDelay, suffix: 's' }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public bombardSlider = new UI.Slider({ left: 0, width: 350, top: 280, height: 30, text: 'Invade', categoryMultiplier: 1, slotMultiplier: 2, stats: [{ name: 'Invade Strength', lookup: config.slotData.bombardPower, suffix: 'per invasion' }, { name: 'Invade Delay', lookup: config.slotData.bombardDelay }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public miningSlider = new UI.Slider({ left: 0, width: 350, top: 320, height: 30, text: 'Mining Strength', categoryMultiplier: 1.5, slotMultiplier: 2, stats: [{ name: 'Mining Rate', lookup: config.slotData.miningRate, suffix: 'extractions per second' }, { name: 'Mining Amount', lookup: config.slotData.miningAmount, suffix: 'gold' }], onSliderValueChanged: this.handleSliderValueChanged, onEnter: this.renderNewShipToolTip });
        public sliders = [this.populationSlider, this.terraformingSlider, this.scanningSlider, this.speedSlider, this.armorSlider, this.shieldsSlider, this.attackSlider, this.bombardSlider, this.miningSlider];

        public newShipNameLabel = new UI.Label({ left: 0, top: 360, width: 90, height: 25, text: 'Ship Name:' });
        public newShipNameTextBox = new UI.TextBox({ left: 90, top: 360, width: 300, height: 25, text: 'Unnamed' });
        public newShipQuantityHeaderLabel = new UI.Label({ left: 0, top: 390, width: 90, height: 25, text: 'Quantity:' });
        public newShipQuantityTextBox = new UI.TextBox({ left: 90, top: 390, width: 100, height: 25, text: '1', quantity: 1, onTextChanged: this.handleNewShipQuantityTextBoxTextChanged });
        public newShipCostHeaderLabel = new UI.Label({ left: 0, top: 420, width: 90, height: 25, text: 'Cost: ◍' });
        public newShipCostLabel = new UI.Label({ left: 90, top: 420, width: 100, height: 25, text: '', costPerShip: 0 });
        public createShipButton = new UI.Button({ left: 0, top: 455, width: 80, height: 40, text: '△ Create', onClick: this.handleCreateShipButtonClicked, onEnter: this.renderNewShipToolTip });
        public savePresetButton = new UI.Button({ left: 90, top: 455, width: 80, height: 40, text: 'Save', onClick: this.handleSavePresetButtonClicked });
        public resetShipButton = new UI.Button({ left: 180, top: 455, width: 80, height: 40, text: 'Reset', onClick: this.handleResetShipButtonClicked });
        public draftButton = new UI.Button({ left: 0, top: 505, width: 80, height: 40, text: '△ Draft', visible: false, onClick: this.handleDraftButtonClicked });

        public presetsPanel = new UI.Panel({ left: 500, top: 0, right: 0, bottom: 0 });

        constructor(parent: GameUI) {
            this.parent = parent;
            this.populationSlider.setupRange(0, config.slotData.colony.length - 1, config.initialSlots.colony, this.sliderVisibleValues, 0);
            this.terraformingSlider.setupRange(0, 1, config.initialSlots.terraforming, this.sliderVisibleValues, 0);
            this.scanningSlider.setupRange(1, config.slotData.scanner.length - 1, config.initialSlots.scanner, this.sliderVisibleValues, 1);
            this.speedSlider.setupRange(1, config.slotData.speeds.length - 1, config.initialSlots.speed, this.sliderVisibleValues, 1);
            this.armorSlider.setupRange(1, config.slotData.armor.length - 1, config.initialSlots.armor, this.sliderVisibleValues, 1);
            this.shieldsSlider.setupRange(0, config.slotData.shields.length - 1, config.initialSlots.shields, this.sliderVisibleValues, 0);
            this.attackSlider.setupRange(0, config.slotData.attackPower.length - 1, config.initialSlots.attack, this.sliderVisibleValues, 0);
            this.bombardSlider.setupRange(0, config.slotData.bombardPower.length - 1, config.initialSlots.bombard, this.sliderVisibleValues, 0);
            this.miningSlider.setupRange(0, config.slotData.miningRate.length - 1, config.initialSlots.mining, this.sliderVisibleValues, 0);

            this.root.controls.push(this.populationSlider, this.terraformingSlider, this.scanningSlider, this.speedSlider, this.armorSlider, this.shieldsSlider, this.attackSlider,
                this.bombardSlider, this.miningSlider, this.newShipNameLabel, this.newShipNameTextBox, this.newShipQuantityHeaderLabel, this.newShipQuantityTextBox, this.newShipCostHeaderLabel, this.newShipCostLabel,
                this.createShipButton, this.savePresetButton, this.resetShipButton, this.draftButton, this.presetsPanel);
        }

        convertSlidersToPreset() {
            var preset = new ShipPreset();
            preset.population = this.populationSlider.value;
            preset.terraform = this.terraformingSlider.value;
            preset.scanning = this.scanningSlider.value;
            preset.speed = this.speedSlider.value;
            preset.armor = this.armorSlider.value;
            preset.shields = this.shieldsSlider.value;
            preset.attack = this.attackSlider.value;
            preset.bombard = this.bombardSlider.value;
            preset.mining = this.miningSlider.value;
            return preset;
        }

        handleSliderValueChanged(sender, value) {
            var panel = gameUI.createShipPanel;
            var preset = panel.convertSlidersToPreset();

            // Start with some generic, low-class terms
            var name = 'Probe';
            if (preset.terraform > 0) name = 'Terraformer';
            if (preset.scanning > 1) name = 'Scout';
            if (preset.mining > 0 && preset.scanning <= 1) name = 'Mining I';
            if (preset.mining > 1 && preset.scanning <= 1) name = 'Mining II';
            if (preset.mining > 2 && preset.scanning <= 1) name = 'Mining III';
            if (preset.bombard > 0) name = 'Transport';

            // Add prefix terms
            if (preset.armor > 2) name = 'Armored ' + name;
            if (preset.speed > 2) name = 'Speedy ' + name;

            // Allow specialisation for attack
            if (preset.attack > 0) name = 'Gunboat I';
            if (preset.attack > 1) name = 'Gunboat II';
            if (preset.attack > 2) name = 'Gunboat III';
            if (preset.attack > 3) name = 'Destroyer';
            if (preset.attack > 4) name = 'Cruiser I';
            if (preset.attack > 5) name = 'Cruiser II';
            if (preset.attack > 6) name = 'Cruiser III';
            if (preset.attack > 7) name = 'Cruiser IV';
            if (preset.attack > 5 && preset.armor > 1) name = 'Battlecruiser I';
            if (preset.attack > 6 && preset.armor > 2) name = 'Battlecruiser II';
            if (preset.attack > 7 && preset.armor > 3) name = 'Battlecruiser III';
            if (preset.bombard > 0) name = 'Troop ' + name;
            if (preset.attack > 6 && preset.armor > 3 && preset.shields > 0 && preset.bombard > 0 && preset.scanning > 1) name = 'Dreadnought I';
            if (preset.attack > 7 && preset.armor > 3 && preset.shields > 1 && preset.bombard > 0 && preset.scanning > 1) name = 'Dreadnought II';

            // Allow specialisation for colony ships
            if (preset.population > 0) name = 'Settler';
            if (preset.population > 1) name = 'Cityship';
            if (preset.population > 2) name = 'Capitol';
            if (preset.population > 0 && preset.terraform > 0) name = 'Terraforming ' + name;

            // Set name
            panel.newShipNameTextBox.text = name;

            // Show cost
            var costPerShip = panel.getCostPerShip();
            panel.newShipCostLabel['costPerShip'] = costPerShip;
            var quantity = panel.getQuantity();
            panel.newShipCostLabel.text = Math.floor(costPerShip * quantity).toString();

            // Create a tooltip describing the ship that will be created
            panel.renderNewShipToolTip();
        }

        private getCostPerShip(): number {

            // Enumerate through all of the sliders in order to calculate figures used in determining cost per ship
            var totalUnits = 0;
            var totalCategories = 0;
            var discount = 0;
            var panel = gameUI.createShipPanel;
            for (var i = 0; i < panel.root.controls.length; i++) {
                var slider = <UI.Slider>panel.root.controls[i];
                if (slider.type == 'Slider' && slider.value > slider.minValue) {

                    // This slider has unlocked a new category
                    totalCategories = totalCategories + (1 * slider['categoryMultiplier']);

                    // Increase number of effective slots, noting that sometimes a slider's slots can be worth more or less than normal
                    totalUnits += (slider.value - slider.minValue) * slider['slotMultiplier'];
                }
            }

            // Calculate cost per ship
            var costPerShip = SHIP_COST_BASE +
                Math.pow(totalCategories * SHIP_COST_PER_CATEGORY_BASE, SHIP_COST_PER_CATEGORY_EXPONENT) +
                Math.pow(totalUnits * SHIP_COST_PER_SLOT_BASE, SHIP_COST_PER_SLOT_EXPONENT);

            // Apply discount
            var effects = galaxy.effects.select((e: Effect) => { return e.calculateShipCost !== undefined });
            for (var i = 0; i < effects.length; i++) {
                var details = effects[i].calculateShipCost();
                discount += details.priceReduction;
            }
            costPerShip -= (costPerShip * discount) | 0;
            return costPerShip;
        }

        private getQuantity(): number {
            var quantity = Math.min(25, Math.max(1, parseInt(gameUI.createShipPanel.newShipQuantityTextBox.text) | 0));
            if (quantity == NaN) quantity = 1;
            return quantity;
        }

        handleCreateShipButtonClicked(sender, e) {

            // Extract the required quantity
            var panel = gameUI.createShipPanel;
            var quantity = panel.getQuantity();
            panel.newShipQuantityTextBox.text = '1';

            // Work on creating the necessary amount of ships
            var shipsCreated = 0;
            var originBody = selected.body;
            var firstShipCode = channel.nextCode;
            var preset = panel.convertSlidersToPreset();
            var costPerShip = <number>panel.newShipCostLabel['costPerShip'];
            var podCount = galaxy.research.artillery.ship.enabled &&
                preset.bombard >= ARTILLERY_BOMBARD_LEVEL_REQUIRED &&
                preset.attack >= ARTILLERY_ATTACK_LEVEL_REQUIRED ? galaxy.research.artillery.ship.pods : 0;
            for (var i = 0; i < quantity; i++) {

                // Validate population requirements
                var population = config.slotData.colony[preset.population];
                if (population > originBody.population) continue;

                // Validate cost requirements (this has to be done last)
                if (!galaxy.spendGold(costPerShip)) continue;

                // Create the ship
                var ship = Ship.create(originBody, preset.clone(), podCount, OwnerType.human, panel.newShipNameTextBox.text);
                ship.cost = costPerShip;
                ship.code = channel.nextCode++;

                // Add to list of selected ships
                if (shipsCreated == 0) {
                    clearSelection();
                }
                shipsCreated++;
                selected.ships.push(ship);
            }

            // Did we create the required number of ships?
            if (shipsCreated == 0) {
                Notices.addMessage(MessageType.fatal, 'Could not create any ships.');
            } else {

                // Notify channel
                channel.invoke.createPresetShips(shipsCreated, originBody.system.code, originBody.code, firstShipCode, preset, podCount, panel.newShipNameTextBox.text, costPerShip);

                // Change displayed state of controls
                panel.root.visible = false;
                panel.parent.shipActionsPanel.root.visible = true;
                Sounds.play(Sounds.items.blip);

                if (shipsCreated != quantity) {
                    Notices.addMessage(MessageType.information, 'Only ' + shipsCreated + ' ships out of the requested ' + quantity + ' could be created.');
                }
            }

            // Make ships fan out if we made more than one
            if (shipsCreated > 1) {
                fanShips();
            }
        }

        handleDraftButtonClicked(sender, e) {

            // Create a preset
            var preset = new ShipPreset();
            preset.population = gameUI.createShipPanel.populationSlider.minValue;
            preset.terraform = gameUI.createShipPanel.terraformingSlider.minValue;
            preset.scanning = gameUI.createShipPanel.scanningSlider.minValue;
            preset.speed = gameUI.createShipPanel.speedSlider.minValue;
            preset.armor = gameUI.createShipPanel.armorSlider.minValue;
            preset.shields = gameUI.createShipPanel.shieldsSlider.minValue;
            preset.attack = gameUI.createShipPanel.attackSlider.enabledValues;
            preset.bombard = gameUI.createShipPanel.bombardSlider.minValue;
            preset.mining = gameUI.createShipPanel.miningSlider.minValue;

            // Create the ship
            var originBody = selected.body;
            originBody.population -= config.draftCost;
            channel.invoke.updateBodyPopulation(originBody.system.code, originBody.code, originBody.population);
            var ship = Ship.create(originBody, preset, 0, OwnerType.human, 'Drafted Defense Ship');
            ship.code = channel.nextCode++;

            // Add to list of selected ships
            clearSelection();
            selected.ships.push(ship);

            // Notify channel
            channel.invoke.createPresetShips(1, originBody.system.code, originBody.code, ship.code, preset, 0, ship.name, 0);

            // Change displayed state of controls
            gameUI.createShipPanel.root.visible = false;
            gameUI.shipActionsPanel.root.visible = true;
            Sounds.play(Sounds.items.blip);

        }

        handleSavePresetButtonClicked(sender, e) {

            // Load existing preset list
            var presets = gameUI.createShipPanel.loadPresets();

            // Create a ship preset based on slider values
            var panel = gameUI.createShipPanel;
            var preset = new ShipPreset();
            preset.name = panel.newShipNameTextBox.text;
            preset.armor = panel.armorSlider.value;
            preset.attack = panel.attackSlider.value;
            preset.bombard = panel.bombardSlider.value;
            preset.terraform = panel.terraformingSlider.value;
            preset.mining = panel.miningSlider.value;
            preset.population = panel.populationSlider.value;
            preset.scanning = panel.scanningSlider.value;
            preset.shields = panel.shieldsSlider.value;
            preset.speed = panel.speedSlider.value;

            // Add the ship preset to the list
            presets.push(preset);
            localStorage.setItem('shipPresets', JSON.stringify(presets));

            // Update list
            gameUI.createShipPanel.updatePresetsList();
        }

        handleLoadShipPresetButtonClicked(sender: UI.UIControl, e: UI.InputArgs) {
            var panel = gameUI.createShipPanel;
            var preset = <ShipPreset>sender.tag;
            panel.newShipNameTextBox.text = preset.name;
            panel.armorSlider.value = Math.min(panel.armorSlider.enabledValues, preset.armor);
            panel.attackSlider.value = Math.min(panel.attackSlider.enabledValues, preset.attack);
            panel.bombardSlider.value = Math.min(panel.bombardSlider.enabledValues, preset.bombard);
            panel.terraformingSlider.value = Math.min(panel.terraformingSlider.enabledValues, preset.terraform);
            panel.miningSlider.value = Math.min(panel.miningSlider.enabledValues, preset.mining);
            panel.populationSlider.value = Math.min(panel.populationSlider.enabledValues, preset.population);
            panel.scanningSlider.value = Math.min(panel.scanningSlider.enabledValues, preset.scanning);
            panel.shieldsSlider.value = Math.min(panel.shieldsSlider.enabledValues, preset.shields);
            panel.speedSlider.value = Math.min(panel.speedSlider.enabledValues, preset.speed);
            panel.handleSliderValueChanged(null, null);
            panel.newShipNameTextBox.text = preset.name;
        }

        handleDeleteShipPresetButtonClicked(sender: UI.UIControl, e: UI.InputArgs) {
            var panel = gameUI.createShipPanel;
            var index = <number>sender.tag;
            var presets = panel.loadPresets();
            presets.splice(index, 1);
            localStorage.setItem('shipPresets', JSON.stringify(presets));
            panel.updatePresetsList();
        }

        handleResetShipButtonClicked(sender, e) {
            var panel = gameUI.createShipPanel;
            panel.armorSlider.value = panel.armorSlider.minValue;
            panel.attackSlider.value = panel.attackSlider.minValue;
            panel.bombardSlider.value = panel.bombardSlider.minValue;
            panel.terraformingSlider.value = panel.terraformingSlider.minValue;
            panel.miningSlider.value = panel.miningSlider.minValue;
            panel.populationSlider.value = panel.populationSlider.minValue;
            panel.scanningSlider.value = panel.scanningSlider.minValue;
            panel.shieldsSlider.value = panel.shieldsSlider.minValue;
            panel.speedSlider.value = panel.speedSlider.minValue;
            panel.handleSliderValueChanged(null, null);
        }

        handleNewShipQuantityTextBoxTextChanged(sender, e) {
            gameUI.createShipPanel.handleSliderValueChanged(null, null);
        }

        renderNewShipToolTip() {
            //#warning A lot of this code is duplicated in getStats()
            var maxLength = 0;
            var sliders = gameUI.createShipPanel.sliders;
            for (var i in sliders) {
                var slider = sliders[i];
                for (var j in slider['stats']) {
                    maxLength = Math.max(maxLength, slider['stats'][j].name.length + 1);
                }
            }
            var toolTip = [{ type: 'title', text: gameUI.createShipPanel.newShipNameTextBox.text }];
            for (var i in sliders) {
                var slider = sliders[i];
                if (slider.value > 0) {
                    var stats = sliders[i]['stats'];
                    for (var j in stats) {
                        var stat = stats[j];
                        var text = stat.name + ':';
                        while (text.length < maxLength) text += ' ';
                        if (stat.lookup !== undefined) {
                            text += ' ' + stat.lookup[slider.value];
                            if (stat.suffix !== undefined) {
                                text += ' ' + stat.suffix;
                            }
                        }
                        toolTip.push({ type: 'text', text: text });
                    }
                }
            }
            toolTipCanvas = ToolTip.render(toolTip);
        }

        private loadPresets(): Array<ShipPreset> {
            var presets: Array<ShipPreset> = [];
            var presetsAsString = localStorage.getItem('shipPresets');
            if (presetsAsString !== null) {
                presets = <Array<ShipPreset>>JSON.parse(presetsAsString);
            }
            return presets;
        }

        updatePresetsList() {
            var panel = this.presetsPanel;
            panel.controls = [];

            // Enumerate through all available presets
            var presets = this.loadPresets();
            for (var i = 0; i < presets.length; i++) {
                var preset = presets[i];

                // Create load button
                var loadButton = new UI.Button({ left: 0, top: i * 30, width: 300, height: 24, text: preset.name, tag: preset });
                loadButton.onClick = this.handleLoadShipPresetButtonClicked;
                panel.controls.push(loadButton);

                // Enable/disable load button
                loadButton.enabled = gameUI.createShipPanel.armorSlider.enabledValues >= preset.armor &&
                    gameUI.createShipPanel.attackSlider.enabledValues >= preset.attack &&
                    gameUI.createShipPanel.bombardSlider.enabledValues >= preset.bombard &&
                    gameUI.createShipPanel.terraformingSlider.enabledValues >= preset.terraform &&
                    gameUI.createShipPanel.miningSlider.enabledValues >= preset.mining &&
                    gameUI.createShipPanel.populationSlider.enabledValues >= preset.population &&
                    gameUI.createShipPanel.scanningSlider.enabledValues >= preset.scanning &&
                    gameUI.createShipPanel.shieldsSlider.enabledValues >= preset.shields &&
                    gameUI.createShipPanel.speedSlider.enabledValues >= preset.speed;

                // Create delete button
                var deleteButton = new UI.Button({ left: 306, top: i * 30, width: 70, height: 24, text: 'Delete', tag: i });
                deleteButton.onClick = this.handleDeleteShipPresetButtonClicked;
                panel.controls.push(deleteButton);
            }
            UI.compute(UI.root, UI.Bounds.create(canvas));
        }

        public getStats(sliders: UI.Slider[], slotIndex: number): string[] {
            var result = [];
            var maxLength = 0;
            for (var i in sliders) {
                for (var j in sliders[i]['stats']) {
                    maxLength = Math.max(maxLength, sliders[i]['stats'][j].name.length + 1);
                }
            }
            for (var i in sliders) {
                var stats = sliders[i]['stats'];
                for (var j in stats) {
                    var stat = stats[j];
                    var text = stat.name + ':';
                    while (text.length < maxLength) text += ' ';
                    if (stat.lookup !== undefined) {
                        text += ' ' + stat.lookup[slotIndex];
                        if (stat.suffix !== undefined) {
                            text += ' ' + stat.suffix;
                        }
                        result.push(text);
                    }
                }
            }
            return result;
        }

    }

}